package com.itmatter.classifier.directdb;

import java.util.Map;
import java.util.Set;

import com.enigmastation.classifier.ClassifierProbability;
import com.itmatter.classifier.DBFisherClassifier;
import java.util.HashMap;
import org.apache.log4j.Logger;

/**
 * Based on initial work from ci-bayes-2.1.0-SNAPSHOT-sources
 * @author Daniel Fisla, dfisla@itmatter.com, ITMATTER Inc., http://www.itmatter.com, Copyright 2010, LGPLv3
 */
public class DBFisherClassifierImpl extends DBNaiveClassifierImpl implements DBFisherClassifier {

    private static final Logger logger = Logger.getLogger(DBFisherClassifierImpl.class.getName());
    protected Map<String, Double> minimums = new HashMap<String, Double>();

    /**
     * 
     * @param category
     * @param minimum
     */
    public void setMinimum(String category, double minimum) {
        minimums.put(category, minimum);
    }

    /**
     * 
     * @param category
     * @return
     */
    public double getMinimum(String category) {
        if (minimums.containsKey(category)) {
            return minimums.get(category);
        }
        return 0.0;
    }

    @Override
    public double getFeatureProbability(String feature, String cat) {
        double clf = super.getFeatureProbability(feature, cat);
        if (clf == 0.0) {
            return 0.0;
        }
        double freqsum = 0.0;

        for (String c : getCategories()) {
            double d = super.getFeatureProbability(feature, c);
            freqsum = freqsum + d;
        }

        return clf / freqsum;
    }

    /**
     * 
     * @param item
     * @param cat
     * @return
     */
    public double fisherprob(Object item, String cat) {
        double p = 1.0;
        Set<String> features = wordLister.getUniqueWords(item);
        for (String f : features) {
            p *= getWeightedFeatureProbability(f, cat);
        }
        double fscore = -2 * Math.log(p);
        return invchi2(fscore, features.size() * 2);
    }

    /**
     * 
     * @param item
     * @param category
     * @return
     */
    public double getFisherProbability(Object item, String category) {
        return fisherprob(item, category);
    }

    /**
     * 
     * @param item
     * @param category
     * @return
     */
    public double getProbabilityForCategory(Object item, String category) {
        return fisherprob(item, category);
    }

    private double invchi2(double chi, int df) {
        double m = chi / 2.0;
        double sum = Math.exp(-m);
        double term = sum;
        for (int i = 1; i < df / 2; i++) {
            term *= m / i;
            sum += term;
        }
        return Math.min(sum, 1.0);
    }

    /**
     * 
     * @param item
     * @param defaultCat
     * @return
     */
    @Override
    public String getClassification(Object item, String defaultCat) {
        if (getCategories().isEmpty()) {
            return defaultCat;
        }
        ClassifierProbability[] probs = getProbabilities(item);
        for (ClassifierProbability p : probs) {
            if (p.getScore() > getMinimum(p.getCategory())) {
                return p.getCategory();
            }
        }
        return defaultCat;
    }
}
